package com.zlb.app.utils;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.ObjectUtil;
import com.google.common.collect.ImmutableMap;
import com.google.common.util.concurrent.ThreadFactoryBuilder;
import com.zlb.app.common.exception.BusinessException;
import org.springframework.util.CollectionUtils;

import java.util.HashMap;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.*;

/**
 * @Desc 多线程工具类
 * @Author zWX1367238
 * @Date 2024-08-16 09:33:05
 **/
public class FutureTaskFeign<T> {

    // 线程工厂
    private static final ThreadFactory namedThreadFactory = new ThreadFactoryBuilder().setNameFormat("dataWash-futureTaskFeignNew-pool-%d").build();

    /**
     * 线程池，用于执行FutureTask
     * 线程池的容量为32,最大线程数为64,空闲时间为0L,时间单位为毫秒,队列容量为10000
     * new ThreadPoolExecutor.AbortPolicy():拒绝策略,默认行为直接抛出一个RejectedExecutionException异常
     * 当线程池关闭、队列已满且已经达到最大线程数时，如果继续提交新任务，会触发这个拒绝策略
     */
    private static final ExecutorService pool = new ThreadPoolExecutor(32, 64, 0L, TimeUnit.MILLISECONDS, new LinkedBlockingQueue<>(10000), namedThreadFactory,
                                                                       new ThreadPoolExecutor.AbortPolicy());

    // 存储FutureTask对象的Map
    private Map<String, FutureTask<T>> futureTaskMap = null;

    // 存储任务执行结果的Map
    private Map<String, Object> result = null;

    // 存储任务配置信息的Map
    private Map<String, Map<String, Object>> config = null;

    // 私有构造函数，防止外部直接实例化
    private FutureTaskFeign() {
    }

    /**
     * 初始化FutureTaskFeign对象
     *
     * @param ints 初始化HashMap时使用的初始容量（可选参数），如果为null或长度不为1或小于等于0，则使用默认值16
     * @param <T>  泛型类型
     * @return 初始化后的FutureTaskFeign对象
     */
    public static <T> FutureTaskFeign<T> init(int... ints) {
        FutureTaskFeign<T> futureTaskFeign = new FutureTaskFeign<>();
        // 如果传入的ints数组不为空，且长度为1，且第一个元素大于0
        if (ints != null && ints.length == 1 && ints[0] > 0) {
            // 初始化futureTaskMap，并设置初始容量为ints[0]
            futureTaskFeign.futureTaskMap = new HashMap<>(ints[0]);
            // 初始化result，并设置初始容量为ints[0]
            futureTaskFeign.result = new HashMap<>(ints[0]);
            // 初始化config，并设置初始容量为ints[0]
            futureTaskFeign.config = new HashMap<>(ints[0]);
        } else {
            // 否则，初始化futureTaskMap，并设置默认初始容量为16
            futureTaskFeign.futureTaskMap = new HashMap<>(16);
            // 初始化result，并设置默认初始容量为16
            futureTaskFeign.result = new HashMap<>(16);
            // 初始化config，并设置默认初始容量为16
            futureTaskFeign.config = new HashMap<>(16);
        }
        // 返回初始化后的FutureTaskFeign对象
        return futureTaskFeign;
    }

    /**
     * 添加带消息的任务，并指定回调函数
     *
     * @param msg            消息内容
     * @param executeBackFn  执行任务并返回结果的函数
     * @param resultCallBack 任务执行完成后的回调函数
     * @param <T>            返回结果类型
     * @return 返回当前FutureTaskFeign对象
     */
    public FutureTaskFeign<T> addByMsg(String msg, CallBackFn<T> executeBackFn, CallBack resultCallBack) {
        if (futureTaskMap != null) {
            // 生成一个随机的任务代码
            String tasKCode = UUID.randomUUID().toString();
            // 将任务代码和对应的FutureTask对象存入futureTaskMap中
            futureTaskMap.put(tasKCode, new FutureTask<>(() -> executeBackFn.execute()));
            // 将任务代码、消息内容和回调函数存入config中
            config.put(tasKCode, ImmutableMap.of("msg", msg, "resultCallBack", resultCallBack));
        }
        return this;
    }

    /**
     * 添加一个异步任务到FutureTaskFeign中，并指定回调函数
     *
     * @param backFn         执行函数，返回任务结果
     * @param resultCallBack 回调函数，处理任务结果
     * @param <T>            任务结果的类型
     * @return 返回当前FutureTaskFeign对象，支持链式调用
     */
    public FutureTaskFeign<T> add(CallBackFn<T> backFn, CallBack resultCallBack) {
        if (futureTaskMap != null) {
            // 生成一个随机的任务码
            String taskCode = UUID.randomUUID().toString();
            // 创建一个新的FutureTask对象，将执行函数backFn.execute()作为参数传入
            futureTaskMap.put(taskCode, new FutureTask<>(() -> backFn.execute()));
            // 将任务码和对应的回调函数resultCallBack存入config中
            config.put(taskCode, ImmutableMap.of("resultCallBack", resultCallBack));
        }
        // 返回当前对象，支持链式调用
        return this;
    }

    /**
     * 添加异步任务到任务队列中，并返回当前FutureTaskFeign对象。
     *
     * @param taskCode 任务的唯一标识码
     * @param backFn   执行异步任务的回调函数
     * @param <T>      任务返回结果的类型
     * @return 返回当前FutureTaskFeign对象，支持链式调用
     */
    public FutureTaskFeign<T> add(String taskCode, CallBackFn<T> backFn) {
        // 如果 futureTaskMap 不为空
        if (futureTaskMap != null) {
            // 将任务添加到 futureTaskMap 中，以 taskCode 为键，创建新的 FutureTask 对象作为值
            // FutureTask 对象执行的任务是调用 backFn.execute()
            futureTaskMap.put(taskCode, new FutureTask<>(() -> backFn.execute()));
        }
        // 返回当前对象
        return this;
    }

    /**
     * 添加一个异步任务到任务队列中，并返回当前FutureTaskFeign对象。
     *
     * @param backFn 执行异步任务的回调函数
     * @param <T>    任务返回结果的类型
     * @return 返回当前FutureTaskFeign对象，支持链式调用
     */
    public FutureTaskFeign<T> add(CallBackFn<T> backFn) {
        if (futureTaskMap != null) {
            // 生成随机的任务码
            String taskCode = UUID.randomUUID().toString();
            // 将任务码和对应的FutureTask对象存入futureTaskMap中
            futureTaskMap.put(taskCode, new FutureTask<>(() -> backFn.execute()));
        }
        // 返回当前对象，支持链式调用
        return this;
    }

    /**
     * 提交任务到线程池执行并处理任务结果
     *
     * @return 返回当前FutureTaskFeign对象，支持链式调用
     * @throws BusinessException 如果处理任务结果时发生异常，则抛出BusinessException异常，并携带异常原因信息
     */
    public FutureTaskFeign<T> submit() {
        if (!CollectionUtils.isEmpty(futureTaskMap)) {
            // 遍历futureTaskMap，提交每个任务到线程池执行
            futureTaskMap.forEach((k, v) -> pool.submit(v));

            // 遍历futureTaskMap，处理每个任务的执行结果
            futureTaskMap.forEach((k, v) -> {
                try {
                    String msg = "";
                    CallBack callBack = null;

                    // 如果config不为空
                    if (CollUtil.isNotEmpty(config)) {
                        // 获取任务配置信息
                        Map<String, Object> configMap = config.get(k);
                        // 获取消息内容
                        msg = (String) configMap.get("msg");
                        // 获取回调函数
                        callBack = (CallBack) configMap.get("resultCallBack");
                    }

                    // 如果回调函数不为空
                    if (callBack != null) {
                        // 调用回调函数处理任务结果
                        callBack.execute(v.get());
                    } else {
                        // 否则将任务结果存入result中
                        result.put(k, v.get());
                    }
                } catch (Exception e) {
                    // 获取异常原因
                    Throwable cause = e.getCause();
                    // 如果异常原因不为空
                    if (ObjectUtil.isNotEmpty(cause)) {
                        // 抛出BusinessException异常，并携带异常原因信息
                        throw new BusinessException(cause.getMessage());
                    }
                }
            });

            // 提交完所有任务后，将futureTaskMap和config置为空，释放内存
            futureTaskMap = null;
            config        = null;
        }
        return this;
    }

    /**
     * 获取结果集
     */
    public Map<String, Object> getResult() {
        return this.result;
    }

    // 定义回调函数接口，用于处理任务执行结果
    public interface CallBack<T> {

        void execute(T restResult);

    }

    // 定义执行任务的函数接口
    public interface CallBackFn<T> {

        T execute();

    }

}
